package models

import (
	"context"
	"database/sql/driver"
	"fmt"
	"time"
)

type MODEL struct {
	ID         int   `gorm:"column:id;type:bigint(20) unsigned;primary_key;AUTO_INCREMENT" json:"id"` // 主键ID
	CreateTime JTime `gorm:"column:create_time;type:datetime;default:CURRENT_TIMESTAMP;comment:创建时间;NOT NULL" json:"create_time"`
	UpdateTime JTime `gorm:"column:update_time;type:datetime;default:CURRENT_TIMESTAMP;comment:更新时间;NOT NULL" json:"update_time"`
}

type JTime struct{ time.Time }
type JDate struct{ time.Time }
type Images struct {
	Url  string `json:"url"`
	Name string `json:"name"`
}

const (
	IsDelNo  = 0
	IsDelYes = 1

	StatusDisabled = 0
	StatusEnabled  = 1

	LanguageZhCN = "zh-CN"
	LanguageEnUS = "en-US"

	GoogleMap = "google"
	BaiduMap  = "baidu"

	EnvLocal = "local"
	EnvProd  = "prod"
	EnvPre   = "pre"

	NoPreCruise            = "S"
	NoPreBrand             = "C"
	NoPreVideo             = "V"
	NoPreCruiseCabin       = "CC"
	NoPreCruiseDeck        = "CD"
	NoPreCruiseDeckLegend  = "CDL"
	NoPreCruisePlay        = "CP"
	NoPreCruiseRestaurant  = "DR"
	NoPreCruiseService     = "CS"
	NoPreCruiseProduct     = "P"
	NoPreCruiseRouteMap    = "CRM"
	NoPrePort              = "PO"
	NoPreFragProds         = "FP"
	NoPreProductTourMapNo  = "MN"
	NoPreFrequentPassenger = "MFP"
	NoPreHomeRecommend     = "R"
	NoPreDestination       = "DS"
	NoPreInterestPoint     = "POI"

	SourceApp     = 1
	SourceBackend = 2
)

var (
	Language    = []string{LanguageZhCN, LanguageEnUS}
	LanguageMap = map[string]string{
		LanguageZhCN: "中文",
		LanguageEnUS: "英文",
	}
	StatusLabel = map[int]string{
		StatusDisabled: "禁用",
		StatusEnabled:  "启用",
	}
	CalibrateLabel = map[int]string{
		StatusDisabled: "未校准",
		StatusEnabled:  "已校准",
	}
	EfficientLabel = map[int]string{
		StatusDisabled: "无效",
		StatusEnabled:  "有效",
	}
	YesNoLabel = map[int]string{
		StatusDisabled: "否",
		StatusEnabled:  "是",
	}
	OnOffLabel = map[int]string{
		StatusDisabled: "关闭",
		StatusEnabled:  "开启",
	}
	Source = map[int]string{
		SourceApp:     "App端",
		SourceBackend: "管理端",
	}
)

// MarshalJSON on JSONTime format Time field with %Y-%m-%d %H:%M:%S
func (jt JTime) MarshalJSON() ([]byte, error) {
	formatted := fmt.Sprintf("\"%s\"", jt.Format(time.DateTime))
	if formatted == "\"0001-01-01 00:00:00\"" {
		return []byte(`""`), nil
	}
	return []byte(formatted), nil
}

// Value insert datetime into mysql need this function.
func (jt JTime) Value() (driver.Value, error) {
	var zeroTime time.Time
	if jt.Time.UnixNano() == zeroTime.UnixNano() {
		return nil, nil
	}
	return jt.Time, nil
}

// Scan value time.Time
func (jt *JTime) Scan(v any) error {
	if value, ok := v.(time.Time); ok {
		*jt = JTime{Time: value}
		return nil
	}
	return fmt.Errorf("can not convert %v to datetime", v)
}

// MarshalJSON on JSONDate format Date field with %Y-%m-%d
func (jd JDate) MarshalJSON() ([]byte, error) {
	formatted := fmt.Sprintf("\"%s\"", jd.Format(time.DateOnly))
	if formatted == "\"0001-01-01\"" {
		return []byte(`""`), nil
	}
	return []byte(formatted), nil
}

// Value insert datetime into mysql need this function.
func (jd JDate) Value() (driver.Value, error) {
	var zeroTime time.Time
	if jd.Time.UnixNano() == zeroTime.UnixNano() {
		return nil, nil
	}
	return jd.Time, nil
}

// Scan value time.Time
func (jd *JDate) Scan(v any) error {
	if value, ok := v.(time.Time); ok {
		*jd = JDate{Time: value}
		return nil
	}
	return fmt.Errorf("can not convert %v to date", v)
}

// PageInfo Paging common input parameter structure
type PageInfo struct {
	Page     int `json:"page_index" form:"page_index"` // 页码
	PageSize int `json:"page_size" form:"page_size"`   // 每页大小
}

func (p *PageInfo) DefPage() int {
	if p.Page <= 0 {
		return 1
	}
	return p.Page
}

func (p *PageInfo) DefPageSize() int {
	if p.PageSize <= 0 || p.PageSize > 10000 {
		return 10
	}
	return p.PageSize
}

func (p *PageInfo) Offset() int {
	return (p.DefPage() - 1) * p.DefPageSize()
}

func AcquireLock(ctx context.Context, lockName string, expiration time.Duration) bool {
	// 尝试设置key值，如果设置成功则获得锁
	ok, _ := RedisClient.SetNX(ctx, lockName, expiration.String(), expiration).Result()

	// 如果设置成功，返回True
	return ok
}
